﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading;
using WorkFlow.Data.Model;

namespace WorkFlow.Data
{
    public class AutomationRun
    {
        Timer tmrPick;

        [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet =
System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
        private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);
        /// <summary>
        /// inerval time
        /// </summary>
        private int _PickTime = 3000;
        SqlHelper _SqlHelper = new SqlHelper();
        DataManager _DataManager;
        WorkFlowTool _WorkFlowTool;
        bool _RequestResult;
        public AutomationRun(SqlHelper sqlHelper, DataManager dataManager, WorkFlowTool workFlowTool)
        {
            //_sqlHelper = sqlHelper;
            _DataManager = dataManager;
            _WorkFlowTool = workFlowTool;
            Start();
        }

        public void Start()
        {
            try
            {
                tmrPick = new System.Threading.Timer(new TimerCallback(tmrPick_Elapsed), null, _PickTime, Timeout.Infinite);
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(ex.Message.ToString(), ex);
            }
        }

        protected void tmrPick_Elapsed(object sender)
        {
            try
            {
                // 内存清理。
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
                }
                DataTable workFlowInfoDT = new DataTable();
                workFlowInfoDT = _SqlHelper.myDataSet("select * from workflowinfo where status='0' or status='1'").Tables[0];

                for (int i = 0; i < workFlowInfoDT.Rows.Count; i++)
                {
                    DataRow dataRow = workFlowInfoDT.Rows[i];
                    string id = "";
                    if (dataRow.Table.Columns.Contains("ID") && dataRow["ID"] != null)
                    {
                        id = dataRow["ID"].ToString();
                    }
                    try
                    {
                        if (dataRow["Status"].ToString() == "0")
                        {
                            // Update wait task to runing
                            //UpdataStatus(id, "1");
                        }
                        DealWorkFlowInfo(dataRow);
                    }
                    catch (Exception ex)
                    {
                        string outMessage;
                        string sql = $"update workflowinfo set Message='{SqlHelper.RemoveSpecialChar((ex.InnerException != null ? ex.InnerException.Message : ex.Message))}' where ID='{id}'";
                        _SqlHelper.ExecuteNonQuery(sql, out outMessage);
                        LogHelper.WriteLog("tmrPick_Elapsed1:", ex);
                    }
                }

            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("tmrPick_Elapsed2:", ex);
            }
            finally
            {
                GC.Collect();
                tmrPick.Change(_PickTime, Timeout.Infinite);
            }
        }

        private bool UpdataStatus(string id, string status)
        {
            string outMessage;
            string sql = $"update workflowinfo set Status='{status}' where ID='{id}'";
            _SqlHelper.ExecuteNonQuery(sql, out outMessage);
            if (outMessage.Equals(string.Empty))
            {
                return true;
            }
            else
            {
                LogHelper.WriteLog(outMessage);
                sql = $"update workflowinfo set Message='{outMessage.Replace("'", "’")}' where ID='{id}'";
                _SqlHelper.ExecuteNonQuery(sql, out outMessage);
                return false;
            }
        }

        /// <summary>
        /// Deal WorkFlowDetail
        /// </summary>
        /// <param name="dataRow">Main WorkFlowInfo</param>
        private void DealWorkFlowInfo(DataRow workFlowInfoRow)
        {
            DataTable detailDT = new DataTable();
            string sql = $"select * from workflowdetail where MainID='{workFlowInfoRow["ID"]}'";
            detailDT = _SqlHelper.myDataSet(sql).Tables[0];
            // Only deal completed node
            foreach (DataRow detailRow in detailDT.Rows)
            {
                // Deal AwaitAutomation
                if (detailRow["Type"].ToString() == "5" && detailRow["Status"].ToString() == "0")
                {
                    DealAwaitAutomation(workFlowInfoRow, detailRow);
                    continue;
                }

                if (detailRow["Status"].ToString() != "2" || detailRow["IsDealed"].ToString() != "0")
                {
                    continue;
                }
                DealWorkFlowDetail(workFlowInfoRow, detailRow);
            }
        }

        /// <summary>
        /// Deal AwaitAutomation
        /// </summary>
        /// <param name="workFlowInfoRow">Main WorkFlow info</param>
        /// <param name="workFlowDetailRow">workFlow Detail info </param>
        private void DealAwaitAutomation(DataRow workFlowInfoRow, DataRow workFlowDetailRow)
        {
            string mainID = workFlowInfoRow["ID"].ToString();
            string detailID = workFlowDetailRow["ID"].ToString();
            string workFlowName = workFlowInfoRow["WorkFlowName"].ToString();
            string fromStepID = workFlowDetailRow["FromStepID"].ToString();
            string currentStepID = workFlowDetailRow["StepID"].ToString();
            // Get all workflow detail info 
            List<WorkFlowDetail> workFlowDetails = _DataManager.GetWorkFlowDetailByMainID(workFlowInfoRow["ID"].ToString());
            // Get previousDetail
            WorkFlowDetail previousDetail = workFlowDetails.Find(x => x.StepID == fromStepID);
            // Get all previous node parameters
            List<ParameterEntity> parameterEntities = _WorkFlowTool.GetOutParametersByDetailID(previousDetail.ID);
            // Get Current Node File
            WorkFlowFile workFlowFile = _WorkFlowTool.GetWorkFlowFileByStepID(workFlowName, currentStepID);
            // Get rule File
            WorkFlowFile ruleFile = _WorkFlowTool.GetPreviousRule(workFlowName, fromStepID, currentStepID);
            // Check rule
            bool bo = CheckRule(ruleFile, parameterEntities);
            if (bo)
            {
                // Notify third party api
                NotifyThirdApi(mainID, detailID, workFlowFile);
            }
        }
        private void DealWorkFlowDetail(DataRow workFlowInfoRow, DataRow workFlowDetailRow)
        {
            string message;
            string sql;
            string mainID = workFlowInfoRow["ID"].ToString();
            string parentID = workFlowInfoRow["ParentID"].ToString();
            string workFlowName = workFlowInfoRow["WorkFlowName"].ToString();
            string currentDetailID = workFlowDetailRow["ID"].ToString();
            string currentID = workFlowDetailRow["StepID"].ToString();
            try
            {
                WorkFlowFile currentWorkFlowFile = _WorkFlowTool.GetCurrentTaskNode(currentDetailID);
                if (currentWorkFlowFile.ShapeType == MasterType.End)
                {
                    DealEndNode(workFlowInfoRow, currentDetailID, currentWorkFlowFile);
                }
                // Get next step config
                List<WorkFlowFile> lineWorkFlowFiles;
                List<WorkFlowFile> nextWorkFlowFiles = _WorkFlowTool.GetNetStepID(currentID, workFlowName, out lineWorkFlowFiles);
                List<ParameterEntity> outParameterEntities = _WorkFlowTool.GetOutParametersByDetailID(currentDetailID);
                int index = 0;
                foreach (WorkFlowFile workFlowFile in nextWorkFlowFiles)
                {
                    string detailsStatus = "0";
                    WorkFlowFile lineWorkFlowFile = lineWorkFlowFiles[index++];
                    bool checkResult = CheckRule(lineWorkFlowFile, outParameterEntities);
                    if (!checkResult && workFlowFile.ShapeType != MasterType.WaitAutomation)
                    {
                        continue;
                    }

                    // Aotumation complete Star and End task
                    if (workFlowFile.ShapeType == MasterType.Start || workFlowFile.ShapeType == MasterType.End)
                    {
                        detailsStatus = "2";
                    }
                    // If config only have In and Out then aotumation complete task
                    if (workFlowFile.Config.ConfigType == ConfigType.None)
                    {
                        detailsStatus = "2";
                    }

                    // If config only have In and Out then aotumation complete task
                    if (workFlowFile.ShapeType == MasterType.IsSubprocess)
                    {
                        detailsStatus = "1";
                    }

                    int shapeType = -1;
                    switch (workFlowFile.ShapeType)
                    {
                        case MasterType.Start:
                            shapeType = 0;
                            break;
                        case MasterType.Automation:
                            shapeType = 1;
                            break;
                        case MasterType.Interface:
                            shapeType = 2;
                            break;
                        case MasterType.IsSubprocess:
                            shapeType = 3;
                            break;
                        case MasterType.End:
                            shapeType = 4;
                            break;
                        case MasterType.WaitAutomation:
                            shapeType = 5;
                            break;
                        default:
                            break;
                    }

                    sql = $"insert into workflowdetail value('0','{mainID}','{currentID}','{workFlowFile.StepID}','{workFlowFile.StepName}','','{detailsStatus}','','',{shapeType},'0','{DateTime.Now.ToString(WorkFlowTool.timeStyle)}','')";
                    string detailID;
                    _SqlHelper.ExecuteNonQueryAndID(sql, out detailID, out message);
                    // Deal Config 
                    if (string.IsNullOrEmpty(message))
                    {
                        // Deal End
                        if (workFlowFile.ShapeType == MasterType.End)
                        {
                            // Update main process status to complate
                            sql = $"update workflowinfo set Status='{detailsStatus}' CompleteTime='{DateTime.Now.ToString(WorkFlowTool.timeStyle)}' where ID='{mainID}'";
                            _SqlHelper.ExecuteNonQuery(sql, out message);

                            if (string.IsNullOrEmpty(parentID))
                            {
                                // Upload parameters to main process
                                // Get current subprocess DB that in parent process
                                sql = $"select * from workflowdetail where MainID='{mainID}'";
                                DataTable subProcessDT = new DataTable();
                                subProcessDT = _SqlHelper.myDataSet(sql).Tables[0];
                                // Get subProcess ID
                                string subProcessID = subProcessDT.Rows[0]["SubProcessMainID"].ToString();
                                try
                                {
                                    // Get SubProcess Detail Row
                                    sql = $"select * from workflowdetail where ID='{subProcessID}'";
                                    DataTable subProcessDetailDT = new DataTable();
                                    subProcessDetailDT = _SqlHelper.myDataSet(sql).Tables[0];
                                    // Get parent main Process
                                    string subProcessStepID = subProcessDetailDT.Rows[0]["StepID"].ToString();
                                    //string parentMainID = subProcessDetailDT.Rows[0]["MainID"].ToString();
                                    // Get parent process workflowinfo
                                    sql = $"select * from workflowinfo where ID='{parentID}'";
                                    DataTable parentWorkFlowInfoDT = new DataTable();
                                    parentWorkFlowInfoDT = _SqlHelper.myDataSet(sql).Tables[0];
                                    // Get current subprocess WorkFlowFile that in parent process
                                    WorkFlowFile subProcessWorkFlowFile = _WorkFlowTool.GetWorkFlowFileByStepID(parentWorkFlowInfoDT.Rows[0]["WorkFlowName"].ToString(), subProcessStepID);
                                    // Get all subProcess parameters
                                    Dictionary<string, string> subProcessParameters = GetOutParameterDict(mainID);
                                    sql = $"select * from parameter where DetailID in (select DetailID from workflowdetail where MainID='{parentID}')";
                                    DataTable parentParameterDT = new DataTable();
                                    parentParameterDT = _SqlHelper.myDataSet(sql).Tables[0];
                                    foreach (Parameter parameter in subProcessWorkFlowFile.Config.OutParameters)
                                    {
                                        string newValue = "";
                                        if (string.IsNullOrWhiteSpace(parameter.Value))
                                        {
                                            if (subProcessParameters.ContainsKey(parameter.Name))
                                            {
                                                newValue = subProcessParameters[parameter.Name];
                                            }
                                        }
                                        else if (Regex.IsMatch(parameter.Value, "^\\{.*?\\}$") && parameter.Value.Length > 2)
                                        {
                                            string key = parameter.Value.Substring(1, parameter.Value.Length - 2);
                                            if (subProcessParameters.ContainsKey(key))
                                            {
                                                newValue = subProcessParameters[key];
                                            }
                                        }
                                        else
                                        {
                                            newValue = parameter.Value;
                                        }

                                        DataRow[] rows = parentParameterDT.Select($"Name='{parameter.Name}'");
                                        if (rows.Length > 0)
                                        {
                                            rows[0][parameter.Name] = newValue;
                                        }
                                        else
                                        {
                                            DataRow newRow = parentParameterDT.NewRow();
                                            newRow[parameter.Name] = newValue;
                                            parentParameterDT.Rows.Add(newRow);
                                        }
                                    }
                                    // Save main process parameters
                                    _SqlHelper.SaveDataTable(sql, parentParameterDT, out message);
                                    // Update SubProcess node to Compelate
                                    sql = $"update workflowdetail set Status='{2}' where ID='{subProcessID}'";
                                    _SqlHelper.ExecuteNonQuery(sql, out message);
                                }
                                catch (Exception ex)
                                {
                                    // Update SubProcess node to Err
                                    sql = $"update workflowdetail set Status='{3}',Message='{SqlHelper.RemoveSpecialChar((ex.InnerException != null ? ex.InnerException.Message : ex.Message))}',IsDealed=1,CompleteTime='{DateTime.Now.ToString(WorkFlowTool.timeStyle)}' where ID='{subProcessID}'";
                                    _SqlHelper.ExecuteNonQuery(sql, out message);
                                }
                            }
                        }
                        // Deal Service
                        if (workFlowFile.Config.ConfigType == ConfigType.Aotumation && (workFlowFile.ShapeType == MasterType.Automation || workFlowFile.ShapeType == MasterType.WaitAutomation))
                        {
                            if (!checkResult)
                            {
                                continue;
                            }
                            // Notify third party api
                            NotifyThirdApi(mainID, detailID, workFlowFile);
                        }
                        // Deal SubProcess
                        else if (workFlowFile.Config.ConfigType == ConfigType.SubProcess && workFlowFile.ShapeType == MasterType.IsSubprocess)
                        {
                            // Save parameters and automation complete start node
                            DealSubProcess(workFlowInfoRow, mainID, detailID, workFlowFile);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // Update SubProcess node to Err
                sql = $"update workflowdetail set Status='{3}',Message='{SqlHelper.RemoveSpecialChar((ex.InnerException != null ? ex.InnerException.Message : ex.Message))}' where ID='{currentDetailID}'";
                _SqlHelper.ExecuteNonQuery(sql, out message);
            }
            // Update the detail status complete
            sql = $"update workflowdetail set IsDealed=1,CompleteTime='{DateTime.Now.ToString(WorkFlowTool.timeStyle)}' where ID='{currentDetailID}'";
            _SqlHelper.ExecuteNonQuery(sql, out message);

        }

        List<RuleDetailEntity> _AllRuleDetailEntities;
        private bool CheckRule(WorkFlowFile lineWorkFlowFile, List<ParameterEntity> parameterEntities)
        {
            bool result = true;
            string ruleName = lineWorkFlowFile.StepName.Trim();
            if (string.IsNullOrEmpty(ruleName))
            {
                return true;
            }
            List<RuleEntity> ruleEntities = _DataManager.GetRule(ruleName);
            RuleEntity ruleEntity = ruleEntities.Find(a => a.Name == ruleName);
            if (ruleEntity == null)
            {
                return true;
            }
            // Current RuleDetail
            List<RuleDetailEntity> items = new List<RuleDetailEntity>();
            _AllRuleDetailEntities = _DataManager.GetRuleDetails();
            // First Rule
            RuleDetailEntity rootNode = _AllRuleDetailEntities.Find(a => a.ID == ruleEntity.RuleDetailID);
            if (rootNode != null)
            {
                items.Add(rootNode);
                // Build RuleDetail
                InitItems(rootNode.ID);

                // Start Check
                bool bo = CheckRuleDetail(rootNode, parameterEntities);
                return bo;
            }

            return result;
        }

        private bool CheckRuleDetail(RuleDetailEntity ruleDetailEntity, List<ParameterEntity> parameterEntities)
        {
            // WoekFlow Value
            string workFlowValue = ruleDetailEntity.Name;
            // RuleDetail Value
            string ruleValue = ruleDetailEntity.Value;
            // If value contains {} then get value from workflow parameter
            if (Regex.IsMatch(ruleValue, "^\\{.*?\\}$") && ruleValue.Length > 2)
            {
                string key = ruleValue.Substring(1, ruleValue.Length - 2);
                ParameterEntity compareEntity = parameterEntities.Find(x => x.Name == key);
                ruleValue = compareEntity?.Value;
            }
            ParameterEntity parameterEntity = parameterEntities.Find(x => x.Name == ruleDetailEntity.Name);
            if (parameterEntity != null)
            {
                workFlowValue = parameterEntity.Value;
            }
            switch (ruleDetailEntity.Type)
            {
                //&
                case 1:
                    foreach (RuleDetailEntity item in ruleDetailEntity.Nodes)
                    {
                        bool bo = CheckRuleDetail(item, parameterEntities);
                        if (!bo)
                        {
                            return false;
                        }
                    }
                    return true;
                // |
                case 2:
                    foreach (RuleDetailEntity item in ruleDetailEntity.Nodes)
                    {
                        bool bo = CheckRuleDetail(item, parameterEntities);
                        if (bo)
                        {
                            return true;
                        }
                    }
                    return false;
                // !
                case 3:
                    if (ruleDetailEntity.Nodes.Count > 0)
                    {
                        bool bo = CheckRuleDetail(ruleDetailEntity.Nodes[0], parameterEntities);
                        return !bo;
                    }
                    return true;
                // =
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                    return Compare(ruleDetailEntity.ValueType, workFlowValue, ruleValue, ruleDetailEntity.Type);
                default:
                    return false;
            }
        }
        /// <summary>
        /// Compare workFlowValue and ruleValue
        /// </summary>
        /// <param name="valueType">value Type (1:String 2:Int 3:Float 4:Double 5:Decimal 6:DateTime 7:Boolean)</param>
        /// <param name="workFlowValue"></param>
        /// <param name="ruleValue"></param>
        /// <param name="compareType"> Compare Type (1:& 2:| 3: ! 4:= 5:!= 6:> 7:>= 8:< 9:<=)</param>
        /// <returns></returns>
        private bool Compare(int valueType, string workFlowValue, string ruleValue, int compareType)
        {
            switch (valueType)
            {
                // string
                case 1:
                    return CompareString(workFlowValue, ruleValue, compareType);
                // int
                case 2:
                case 3:
                case 4:
                case 5:
                    return CompareDecimal(workFlowValue, ruleValue, compareType);
                // DataTime
                case 6:
                    return CompareDateTime(workFlowValue, ruleValue, compareType);
                // Boolean
                case 7:
                    return CompareBool(workFlowValue, ruleValue, compareType);
                default:
                    return false;
            }
        }
        /// <summary>
        /// Compare String
        /// </summary>
        /// <param name="workFlowValue"></param>
        /// <param name="ruleValue"></param>
        /// <param name="compareType">Compare Type (1:& 2:| 3: ! 4:= 5:!= 6:> 7:>= 8:< 9:<=)</param>
        /// <returns></returns>
        private bool CompareString(string workFlowValue, string ruleValue, int compareType)
        {
            switch (compareType)
            {
                case 4:
                    return workFlowValue.Equals(ruleValue);
                case 5:
                    return !workFlowValue.Equals(ruleValue);
                default:
                    return false;
            }
        }
        /// <summary>
        /// Compare Decimal
        /// </summary>
        /// <param name="workFlowValue"></param>
        /// <param name="ruleValue"></param>
        /// <param name="compareType">Compare Type (1:& 2:| 3: ! 4:= 5:!= 6:> 7:>= 8:< 9:<=)</param>
        /// <returns></returns>
        private bool CompareDecimal(string workFlowValue, string ruleValue, int compareType)
        {
            decimal workFlowValue_Decimal;
            decimal ruleValue_Decimal;
            if (!decimal.TryParse(workFlowValue, out workFlowValue_Decimal)
            || !decimal.TryParse(ruleValue, out ruleValue_Decimal))
            {
                return false;
            }
            switch (compareType)
            {
                case 4:
                    return workFlowValue_Decimal == ruleValue_Decimal;
                case 5:
                    return workFlowValue_Decimal != ruleValue_Decimal;
                case 6:
                    return workFlowValue_Decimal > ruleValue_Decimal;
                case 7:
                    return workFlowValue_Decimal >= ruleValue_Decimal;
                case 8:
                    return workFlowValue_Decimal < ruleValue_Decimal;
                case 9:
                    return workFlowValue_Decimal <= ruleValue_Decimal;
                default:
                    return false;
            }
        }
        /// <summary>
        /// Compare DateTime
        /// </summary>
        /// <param name="workFlowValue"></param>
        /// <param name="ruleValue"></param>
        /// <param name="compareType">Compare Type (1:& 2:| 3: ! 4:= 5:!= 6:> 7:>= 8:< 9:<=)</param>
        /// <returns></returns>
        private bool CompareDateTime(string workFlowValue, string ruleValue, int compareType)
        {
            DateTime workFlowValue_DateTime;
            DateTime ruleValue_DateTime;
            if (!DateTime.TryParse(workFlowValue, out workFlowValue_DateTime)
                || !DateTime.TryParse(ruleValue, out ruleValue_DateTime))
            {
                return false;
            }
            switch (compareType)
            {
                case 4:
                    return workFlowValue_DateTime == ruleValue_DateTime;
                case 5:
                    return workFlowValue_DateTime != ruleValue_DateTime;
                case 6:
                    return workFlowValue_DateTime > ruleValue_DateTime;
                case 7:
                    return workFlowValue_DateTime >= ruleValue_DateTime;
                case 8:
                    return workFlowValue_DateTime < ruleValue_DateTime;
                case 9:
                    return workFlowValue_DateTime <= ruleValue_DateTime;
                default:
                    return false;
            }
        }

        /// <summary>
        /// Compare Bool
        /// </summary>
        /// <param name="workFlowValue"></param>
        /// <param name="ruleValue"></param>
        /// <param name="compareType">Compare Type (1:& 2:| 3: ! 4:= 5:!= 6:> 7:>= 8:< 9:<=)</param>
        /// <returns></returns>
        private bool CompareBool(string workFlowValue, string ruleValue, int compareType)
        {
            bool workFlowValue_bool;
            bool ruleValue_bool;
            if (!bool.TryParse(workFlowValue, out workFlowValue_bool)
                || !bool.TryParse(ruleValue, out ruleValue_bool))
            {
                return false;
            }
            switch (compareType)
            {
                case 4:
                    return workFlowValue_bool.Equals(ruleValue_bool);
                case 5:
                    return !workFlowValue_bool.Equals(ruleValue_bool);
                default:
                    return false;
            }
        }
        private void InitItems(int id)
        {
            RuleDetailEntity parentNode = _AllRuleDetailEntities.Find(a => a.ID == id);
            List<RuleDetailEntity> ruleDetailEntities = _AllRuleDetailEntities.FindAll(a => a.ParentID == id);
            parentNode.Nodes = ruleDetailEntities;
            foreach (RuleDetailEntity item in ruleDetailEntities)
            {
                InitItems(item.ID);
            }
        }

        private void DealEndNode(DataRow workFlowInfoRow, string detailID, WorkFlowFile endWorkFlowFile)
        {
            // Update main process complete 
            string sql = $"update workflowinfo set status=2 where ID='{workFlowInfoRow["ID"]}'";
            string message;
            _SqlHelper.ExecuteNonQuery(sql, out message);
            // Update subprocess node complete
            sql = $"select * from workflowdetail where SubProcessMainID='{workFlowInfoRow["ID"]}'";
            DataTable subProcessDT = _SqlHelper.myDataSet(sql).Tables[0];
            if (subProcessDT.Rows.Count > 0)
            {
                sql = $"update workflowdetail set Status = 2 where ID='{subProcessDT.Rows[0]["ID"]}'";
                _SqlHelper.ExecuteNonQuery(sql, out message);
            }
        }

        private void DealSubProcess(DataRow workFlowInfoRow, string mainID, string detailID, WorkFlowFile workFlowFile)
        {
            // Get all in parameters
            Dictionary<string, string> dict = GetInParameterDict(mainID, workFlowFile);
            // Insert data to workflowinfo
            string sql = $"insert into workflowinfo value('0','{workFlowFile.Config.TypeValue}','','1','','{mainID}','{DateTime.Now.ToString(WorkFlowTool.timeStyle)}','')";
            string id;
            string message;
            _SqlHelper.ExecuteNonQueryAndID(sql, out id, out message);

            // Update SubProcessMainID
            sql = $"update workflowdetail set SubProcessMainID ='{id}' where ID='{detailID}'";
            _SqlHelper.ExecuteNonQuery(sql, out message);

            // Automation complete Start node
            WorkFlowFile startWorkFlowFile = _WorkFlowTool.GetStarStepIDbyWorkFlowName(workFlowFile.Config.TypeValue);
            sql = $"insert into workflowdetail value('0','{id}','-1','{startWorkFlowFile.StepID}','Start','','2','','','0','0','{DateTime.Now.ToString(WorkFlowTool.timeStyle)}','')";
            int count = _SqlHelper.ExecuteNonQueryAndID(sql, out detailID, out message);
            // Save all parameters
            DataTable allParameterDT = new DataTable();
            sql = $"select * from parameter where DetailID='{detailID}'";
            allParameterDT = _SqlHelper.myDataSet(sql).Tables[0];
            foreach (string key in dict.Keys)
            {
                DataRow newRow = allParameterDT.NewRow();
                newRow["ID"] = "0";
                newRow["DetailID"] = detailID;
                newRow["Name"] = key;
                newRow["Value"] = dict[key];
                allParameterDT.Rows.Add(newRow);
            }
            count = _SqlHelper.SaveDataTable(sql, allParameterDT, out message);
            if (count == 0)
            {
                LogHelper.WriteLog("RunWorkFlow:Step2:" + message);
            }
        }
        private Dictionary<string, string> GetInParameterDict(string mainID, WorkFlowFile workFlowFile)
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();
            string sql = $"select * from workflowdetail where MainID='{mainID}'";
            DataTable allDetailDT = _SqlHelper.myDataSet(sql).Tables[0];
            // Get Start row 
            DataRow startRow = allDetailDT.Rows[0];
            string startDetailID = startRow["ID"].ToString();
            sql = $"select * from parameter where DetailID in (select DetailID from workflowdetail where MainID='{mainID}')";
            DataTable parameterDT = _SqlHelper.myDataSet(sql).Tables[0];
            // Add main workflow parameters
            foreach (DataRow row in parameterDT.Rows)
            {
                if (row["DetailID"].ToString() == startDetailID)
                {
                    string name = row["Name"].ToString();
                    string value = row["Value"].ToString();
                    dict[name] = value;
                }
            }
            // Add current parameters
            foreach (Parameter parameter in workFlowFile.Config.InParameters)
            {
                string newValue = parameter.Value;
                if (Regex.IsMatch(parameter.Value, "^\\{.*?\\}$") && parameter.Value.Length > 2)
                {
                    string key = parameter.Value.Substring(1, parameter.Value.Length - 2);
                    DataRow[] rows = parameterDT.Select($"Name='{key}'");
                    if (rows.Length > 0)
                    {
                        newValue = rows[0]["Value"] != null ? rows[0]["Value"].ToString() : "";
                    }
                }
                dict[parameter.Name] = newValue;
            }
            return dict;
        }
        private Dictionary<string, string> GetOutParameterDict(string mainID)
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();
            string sql = $"select * from workflowdetail where MainID='{mainID}'";
            DataTable allDetailDT = _SqlHelper.myDataSet(sql).Tables[0];
            foreach (DataRow row in allDetailDT.Rows)
            {
                dict[row["Name"].ToString()] = row["Value"].ToString();
            }
            // Get all process parameters
            //sql = $"select * from parameter where DetailID in (select DetailID from workflowdetail where MainID='{mainID}')";
            //DataTable parameterDT = _sqlHelper.myDataSet(sql).Tables[0];

            //// Add current parameters
            //foreach (Parameter parameter in workFlowFile.Config.OutParameters)
            //{
            //    DataRow[] rows = parameterDT.Select($"Name='{parameter.Name}'");
            //    if (rows.Length > 0 && !dict.ContainsKey(parameter.Name))
            //    {
            //        dict[parameter.Name] = rows[0]["Value"].ToString();
            //    }
            //}
            return dict;
        }

        class APIParameter
        {
            string _MainID;
            public string MainID
            {
                get { return _MainID; }
                set { _MainID = value; }
            }
            string _DetailID;
            public string DetailID
            { get { return _DetailID; } set { _DetailID = value; } }
            WorkFlowFile _WorkFlowFile;
            public WorkFlowFile WorkFlowFile
            {
                get { return _WorkFlowFile; }
                set { _WorkFlowFile = value; }
            }
        }

        private void NotifyThirdApi(string mainID, string detailID, WorkFlowFile workFlowFile)
        {
            APIParameter parameter = new APIParameter();
            parameter.MainID = mainID;
            parameter.DetailID = detailID;
            parameter.WorkFlowFile = workFlowFile;

            BackgroundWorker backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += BackgroundWorker_DoWork;
            backgroundWorker.RunWorkerAsync(parameter);
        }


        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            APIParameter parameter = e.Argument as APIParameter;
            string mainID = parameter.MainID;
            string detailID = parameter.DetailID;
            WorkFlowFile workFlowFile = parameter.WorkFlowFile;
            string timeOut = workFlowFile.TimeOut;
            int requestCount = workFlowFile.RequestRequestCount;
            int hour = 0, minute = 0, second = 0;
            string[] splitTime = timeOut.Split(':');
            if (splitTime.Length == 3)
            {
                int.TryParse(splitTime[0].TrimStart('0'), out hour);
                int.TryParse(splitTime[1].TrimStart('0'), out minute);
                int.TryParse(splitTime[2].TrimStart('0'), out second);
            }
            // TimeOut to second
            int allSecond = hour * 60 * 60 + minute * 60 + second;
            // The Interval Time
            double intervalTime = (double)allSecond / (double)requestCount;
            intervalTime = intervalTime * 1000;
            for (int index = 0; index < requestCount; index++)
            {
                try
                {
                    // Update Status to pulled
                    string sql = $"update workflowdetail set  Status='1' where ID='{detailID}'";
                    string messageStr;
                    _SqlHelper.ExecuteNonQuery(sql, out messageStr);
                    Dictionary<string, string> data = GetInParameterDict(mainID, workFlowFile);
                    data["ServiceCode"] = workFlowFile.Config.TypeValue;
                    data["WorkFlowDetailID"] = detailID;
                    HttpClient httpClient = new HttpClient();
                    string str = SerializeJson<Dictionary<string, string>>(data);
                    //var content = new StringContent(str);
                    //content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                    //HttpResponseMessage message = httpClient.PostAsync(WorkFlowTool.ThirdApiAddress, content).Result;
                    HttpResponseMessage message = httpClient.GetAsync(WorkFlowTool.ThirdApiAddress + $"?parameters={str}").Result;
                    bool result = message.StatusCode == System.Net.HttpStatusCode.OK;
                    if (result)
                    {
                        _RequestResult = true;
                        sql = $"update workflowdetail set CompleteTime='{DateTime.Now.ToString(WorkFlowTool.timeStyle)}' where ID='{detailID}'";
                        _SqlHelper.ExecuteNonQuery(sql, out messageStr);
                        break;
                    }
                    Thread.Sleep(((int)intervalTime));
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLog("NotifyThirdApi:", ex);
                    string sql = $"update workflowdetail set Status='3',Message='{SqlHelper.RemoveSpecialChar((ex.InnerException != null ? ex.InnerException.Message : ex.Message))}',CompleteTime='{DateTime.Now.ToString(WorkFlowTool.timeStyle)}' where ID='{detailID}'";
                    string messageStr;
                    _SqlHelper.ExecuteNonQuery(sql, out messageStr);
                    Thread.Sleep(((int)intervalTime));
                }
            }
        }

        class ThirdDataModel
        {
            string _ServiceCode;
            public string ServiceCode
            {
                get { return _ServiceCode; }
                set
                {
                    _ServiceCode = value;
                }
            }

            Dictionary<string, string> _KeyValuePairs;
            public Dictionary<string, string> KeyValuePairs
            {
                get { return _KeyValuePairs; }
                set { _KeyValuePairs = value; }
            }

        }

        public static string SerializeJson<T>(T obj, int indentation = 0, char indentchar = ' ')
        {
            StringWriter writer = new StringWriter();
            JsonTextWriter jsoonWriter = new JsonTextWriter(writer)
            {
                Formatting = Formatting.Indented,
                Indentation = indentation,
                IndentChar = indentchar
            };
            JsonSerializer serializer = new JsonSerializer();
            serializer.Serialize(jsoonWriter, obj);
            return writer.ToString();
        }
        public static T DeserializeJson<T>(string json)
        {
            return JsonConvert.DeserializeObject<T>(json);
        }



    }
}
